home *** CD-ROM | disk | FTP | other *** search
- /* ======================================================================== *
- * Arrows.c -- a BOOPSI class implementing increment / decrement arrows
- * By Talin.
- * Copyright © 1991 Sylvan Technical Arts
- * ======================================================================== */
-
- #include "std_headers.h"
- #include <intuition/cghooks.h>
- #include <intuition/gadgetclass.h>
- #include <intuition/classes.h>
- #include <intuition/imageclass.h>
- #include <utility/tagitem.h>
- #include <utility/hooks.h>
- #include <clib/alib_protos.h>
- #include <math.h>
-
- #include "arrows.h"
-
- extern struct Library *IntuitionBase,
- *UtilityBase,
- *GadToolsBase,
- *GfxBase;
-
- #define INCREMENT GACT_ALTKEYMAP /* overload this gadget flag */
-
- #define clamp(a,b,c) min( max( a, b ), c ) /* constrain b between a and c */
-
- struct ArrowButton {
- ULONG min, /* minimum value */
- max, /* maximum value */
- current; /* current internal value */
- UWORD rate, /* rate of increment */
- rate_increase, /* % speed increase per tick */
- rate_max; /* maximum speed */
- };
-
- void __asm AsymBevel( register __a0 struct RastPort *rp,
- register __a1 struct IBox *b,
- register __d0 LONG ulpen,
- register __d1 LONG lrpen,
- register __d2 LONG fillpen,
- register __d3 WORD side );
-
- void SetupGadgetIBox( struct Gadget *gadget, struct IBox *domain, struct IBox *box )
- {
- box->Left = gadget->LeftEdge;
- box->Top = gadget->TopEdge;
- box->Width = gadget->Width;
- box->Height = gadget->Height;
-
- if (gadget->Flags & GRELRIGHT) box->Left += domain->Width;
- if (gadget->Flags & GRELBOTTOM) box->Top += domain->Height;
-
- if (gadget->Flags & GRELWIDTH) box->Width += domain->Width;
- if (gadget->Flags & GRELHEIGHT) box->Height += domain->Height;
- }
-
- /* GM_RENDER method handler */
-
- static void arrowdraw(Class *cl, struct gpRender *msg,struct Gadget *g)
- {
- if (msg->gpr_Redraw == GREDRAW_REDRAW || msg->gpr_Redraw == GREDRAW_UPDATE)
- { struct IBox left_box,
- right_box;
- struct GadgetInfo *gi = msg->gpr_GInfo;
- struct RastPort *rp = msg->gpr_RPort;
- UWORD *pens = gi->gi_DrInfo->dri_Pens;
- BOOL dec_selected = 0,
- inc_selected = 0;
- WORD symbol_diag_w,
- symbol_diag_h;
- WORD x_center,
- y_center;
- WORD symbol_height,
- symbol_y1,
- symbol_y2,
- symbol_y3,
- symbol_y4;
- WORD sx1,
- sx2;
-
- SetupGadgetIBox( g, &gi->gi_Domain, &right_box);
-
- if (g->Flags & GFLG_SELECTED)
- { if (g->Activation & INCREMENT) inc_selected = TRUE;
- else dec_selected = TRUE;
- }
-
- left_box = right_box;
- left_box.Width = right_box.Width / 2;
- right_box.Width = right_box.Width - left_box.Width;
- right_box.Left += left_box.Width;
-
- symbol_diag_w = MIN( left_box.Width - 5, 7);
- symbol_diag_w = MIN( symbol_diag_w, left_box.Height / 3 );
- symbol_diag_h = clamp(3, (left_box.Height - 3) / 2, symbol_diag_w );
-
- symbol_height = symbol_diag_h + symbol_diag_h - (right_box.Height & 1);
-
- x_center = (left_box.Width - symbol_diag_w) / 2;
- y_center = (right_box.Height - symbol_height) / 2;
-
- /* Draw 1st arrow button */
-
- symbol_height--;
- symbol_diag_h--;
- symbol_diag_w--;
- symbol_y1 = left_box.Top + y_center;
- symbol_y2 = symbol_y1 + symbol_diag_h;
- symbol_y4 = symbol_y1 + symbol_height - symbol_diag_h;
- symbol_y3 = symbol_y1 + symbol_height;
-
- AsymBevel( rp, &left_box,
- pens[ dec_selected ? SHADOWPEN : SHINEPEN ],
- pens[ dec_selected ? SHINEPEN : SHADOWPEN ],
- pens[ dec_selected ? FILLPEN : BACKGROUNDPEN ],
- 0 );
-
- /* draw inner part of right-hand box */
-
- SetAPen(rp,pens[ TEXTPEN ]);
-
- sx1 = left_box.Left + 1 + x_center;
- sx2 = sx1 + symbol_diag_w;
-
- Move( rp, sx1, symbol_y2 );
- Draw( rp, sx2, symbol_y1 );
- Move( rp, sx1, symbol_y4 );
- Draw( rp, sx2, symbol_y3 );
-
- Move( rp, sx1 + 1, symbol_y2 );
- Draw( rp, sx2, symbol_y1 + 1 );
- Move( rp, sx1 + 1, symbol_y4 );
- Draw( rp, sx2, symbol_y3 - 1 );
-
- AsymBevel( rp, &right_box,
- pens[ inc_selected ? SHADOWPEN : SHINEPEN ],
- pens[ inc_selected ? SHINEPEN : SHADOWPEN ],
- pens[ inc_selected ? FILLPEN : BACKGROUNDPEN ],
- 1 );
-
- /* draw inner part of right-hand box */
-
- SetAPen(rp,pens[ TEXTPEN ]);
-
- sx1 = right_box.Left + x_center;
- sx2 = sx1 + symbol_diag_w;
-
- Move( rp, sx2, symbol_y2 );
- Draw( rp, sx1, symbol_y1 );
- Move( rp, sx2, symbol_y4 );
- Draw( rp, sx1, symbol_y3 );
-
- Move( rp, sx2 - 1, symbol_y2 );
- Draw( rp, sx1, symbol_y1 + 1 );
- Move( rp, sx2 - 1, symbol_y4 );
- Draw( rp, sx1, symbol_y3 - 1 );
- }
- }
-
- static int TestHit(struct gpInput *msg,struct Gadget *g)
- { struct IBox gbox;
- short x = msg->gpi_Mouse.X,
- y = msg->gpi_Mouse.Y;
-
- SetupGadgetIBox(g,&msg->gpi_GInfo->gi_Domain,&gbox);
-
- if (x >= 0 && y >= 0 && x < gbox.Width && y < gbox.Height)
- return (x > gbox.Width / 2) ? ARROWSTATE_INC : ARROWSTATE_DEC;
-
- return 0;
- }
-
- /* GM_HANDLEINPUT method handler */
-
- static long arrowhandle(Class *cl, struct gpInput *msg,struct Gadget *g)
- {
- struct RastPort *rp;
- long result = GMR_MEACTIVE;
- BOOL render = FALSE, /* TRUE if we need to re-render */
- update = FALSE, /* TRUE if we need to re-calc */
- notify = FALSE; /* TRUE if we need to broadcast */
- WORD verify = g->Activation & GACT_RELVERIFY ? GMR_VERIFY : 0;
- struct ArrowButton *ab = (struct ArrowButton *)INST_DATA( cl, g );
- static timer_delay;
-
- /* Handle input messages */
-
- if (msg->MethodID == GM_GOACTIVE) /* classify type of hit */
- {
- if (msg->gpi_IEvent == NULL) return GMR_NOREUSE;
- ab->rate = 100;
-
- g->Flags |= GFLG_SELECTED;
- if (TestHit(msg,g) == ARROWSTATE_INC) g->Activation |= INCREMENT;
- else g->Activation &= ~INCREMENT;
-
- timer_delay = 2;
-
- render = notify = update = TRUE;
- }
-
- if (msg->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
- {
- if (msg->gpi_IEvent->ie_Code == (UBYTE)(IECODE_LBUTTON+IECODE_UP_PREFIX))
- {
- g->Flags &= ~GFLG_SELECTED;
- result = GMR_NOREUSE | verify;
- render = TRUE;
- }
- else if (msg->gpi_IEvent->ie_Code == (UBYTE)IECODE_RBUTTON)
- {
- /* check for menu button hit */
-
- g->Flags &= ~GFLG_SELECTED;
- result = GMR_REUSE | verify;
- render = TRUE;
- }
- else
- { WORD oldflags = g->Flags,
- hit = TestHit(msg,g),
- current_state;
-
- current_state = (g->Activation & INCREMENT) ? ARROWSTATE_INC : ARROWSTATE_DEC;
-
- if (current_state == hit) g->Flags |= GFLG_SELECTED;
- else g->Flags &= ~GFLG_SELECTED;
-
- if (g->Flags != oldflags) render = TRUE;
- }
- }
- else if (msg->gpi_IEvent->ie_Class == IECLASS_TIMER)
- {
- if (timer_delay > 0) timer_delay--;
- else
- {
- update = TRUE;
- ab->rate = ab->rate * ab->rate_increase / 100;
- if (ab->rate > ab->rate_max) ab->rate = ab->rate_max;
- }
- }
-
- /* increment or decrement internal value */
-
- if (update)
- { LONG rate = ab->rate / 100;
- LONG newval;
-
- if (rate < 1) rate = 1;
- if (!(g->Activation & INCREMENT)) rate = -rate;
- newval = clamp(ab->min,ab->current + rate,ab->max);
- if (newval != ab->current)
- { ab->current = newval;
- notify = TRUE;
- }
- }
-
- /* re-render the gadget */
-
- if (render && (rp = ObtainGIRPort(msg->gpi_GInfo)))
- {
- DoMethod((Object *)g,GM_RENDER,msg->gpi_GInfo,rp,GREDRAW_UPDATE);
- ReleaseGIRPort(rp);
- }
-
- /* notify others that we changed */
-
- if (notify)
- { struct TagItem output_tags[ 4 ],
- *tagout = output_tags;
- WORD flags = OPUF_INTERIM;
-
- /* build a conditional tag list */
-
- tagout->ti_Tag = GA_ID;
- tagout->ti_Data = g->GadgetID;
- tagout++;
-
- tagout->ti_Tag = ARROW_Current;
- tagout->ti_Data = ab->current;
- tagout++;
-
- if (result & GMR_VERIFY)
- { tagout->ti_Tag = ARROW_State;
- tagout->ti_Data = 0;
- tagout++;
- flags = 0;
- }
- else if (msg->MethodID == GM_GOACTIVE)
- { tagout->ti_Tag = ARROW_State;
- tagout->ti_Data = g->Activation & INCREMENT ? ARROWSTATE_INC : ARROWSTATE_DEC;
- tagout++;
- }
-
- tagout->ti_Tag = TAG_DONE;
-
- /* send notification */
-
- DoMethod( (Object *)g, OM_NOTIFY, output_tags, msg->gpi_GInfo, flags );
- }
-
- return result;
- }
-
- /* ============================================================================ *
- * set ArrowButton attributes
- * ============================================================================ */
-
- static int setArrowButtonAttrs( Class *cl, Object *o, struct opSet *msg )
- { struct TagItem *tags = msg->ops_AttrList,
- *tlist = tags;
- struct ArrowButton *ab = INST_DATA( cl, o );
- ULONG tagval;
-
- /* iterate through the tags and setup what values are needed */
-
- while (tags = NextTagItem(&tlist))
- {
- tagval = tags->ti_Data;
- switch (tags->ti_Tag) {
-
- case ARROW_Min: ab->min = tagval; break;
- case ARROW_Max: ab->max = tagval; break;
- case ARROW_Current: ab->current = tagval; break;
- case ARROW_IncreaseRate: ab->rate_increase = tagval + 100; break;
- case ARROW_MaxRate: ab->rate_max = tagval * 100; break;
- }
- }
- ab->current = clamp(ab->min,ab->current,ab->max);
- return 0;
- }
-
- /* ============================================================================ *
- * dispatch function for the ArrowButton Class
- * ============================================================================ */
-
- static long __asm __saveds ourhook (
- register __a0 Class *cl,
- register __a1 struct gpInput *msg,
- register __a2 struct Gadget *g,
- register __a6 struct Library *IntuitionBase)
- { long refresh = 0;
- struct ArrowButton *ab;
- static struct ArrowButton init_ab = { 0,100,0,100,10000 };
-
- switch ( msg->MethodID ) {
-
- case GM_RENDER:
- arrowdraw(cl, (struct gpRender *)msg, g);
- break;
-
- case GM_HITTEST:
- return GMR_GADGETHIT;
-
- case GM_GOACTIVE:
- case GM_HANDLEINPUT:
- return arrowhandle(cl,msg,g);
-
- case GM_GOINACTIVE:
- break;
-
- case OM_NEW:
- g = (struct Gadget *)DoSuperMethodA( cl, (Object *)g, (Msg)msg);
- if (g == NULL) return NULL;
-
- ab = INST_DATA( cl, g );
- *ab = init_ab;
- setArrowButtonAttrs( cl, (Object *)g, (struct opSet *)msg );
-
- return (long)g;
-
- case OM_SET:
- DoSuperMethodA( cl, (Object *)g, (Msg)msg ); /* set attibutes */
- refresh |= setArrowButtonAttrs( cl, (Object *)g, (struct opSet *)msg );
- return 0;
-
- default:
- return (LONG) DoSuperMethodA( cl, (Object *)g, (Msg)msg );
- }
- return 0;
- }
-
- /* ============================================================================ *
- * initArrowButtonClass: create data used by all Arrow Buttons
- * ============================================================================ */
-
- Class *initArrowButtonClass(void)
- { Class *cl;
-
- if (cl = MakeClass( /* Ask Intuition to make it */
- NULL, /* Class ID (none) */
- "gadgetclass", NULL, /* superclass is public, tho... */
- sizeof (struct ArrowButton), /* Size of instance data */
- 0 )) /* No flags... */
- {
- cl->cl_Dispatcher.h_Entry = (HOOKFUNC)ourhook;
- cl->cl_Dispatcher.h_SubEntry = NULL;
- cl->cl_Dispatcher.h_Data = 0L;
- }
-
- return cl;
- }
-
- LONG freeArrowButtonClass(Class *cl)
- {
- return (LONG)FreeClass(cl);
- }
-